package model

import (
	"errors"
	"fmt"
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"gorm.io/gorm"
)

type CasbinRule struct {
	ID     int    `json:"id" gorm:"id"`
	PType  string `json:"pType" gorm:"column:ptype" description:"策略类型"`
	RoleId string `json:"roleId" gorm:"column:v0" description:"角色ID"`
	Path   string `json:"path" gorm:"column:v1" description:"api路径"`
	Method string `json:"method" gorm:"column:v2" description:"访问方法"`
}

func (rule *CasbinRule) TableName() string {
	return "casbin_rule"
}

type (
	CasbinRuleModel interface {
		Insert(rule CasbinRule) error
		Update(rule CasbinRule) error
		List() []CasbinRule
		Casbin() *casbin.Enforcer
	}
	defaultCasbinRuleModel struct {
		conn  *gorm.DB
		table string
	}
)

func NewCasbinRuleModel(user, pwd, host, dbName string, port int) CasbinRuleModel {
	return defaultCasbinRuleModel{
		table: "casbin_rule",
		conn:  initMysqlSource(user, pwd, host, dbName, port),
	}
}
func (d defaultCasbinRuleModel) Insert(rule CasbinRule) error {
	e := d.Casbin()
	if success, _ := e.AddPolicy(rule.RoleId, rule.Path, rule.Method); success == false {
		return errors.New("存在相同的权限，添加失败")
	}
	return nil
}
func (d defaultCasbinRuleModel) Update(rule CasbinRule) error {
	result := d.conn.Model(&CasbinRule{}).Where("v0 = ?", rule.RoleId).Updates(CasbinRule{Path: rule.Path, Method: rule.Method})
	return result.Error
}
func (d defaultCasbinRuleModel) List() []CasbinRule {
	var ruleList []CasbinRule
	d.conn.Find(&ruleList)
	return ruleList
}
func (d defaultCasbinRuleModel) Casbin() *casbin.Enforcer {
	adapter, _ := gormadapter.NewAdapterByDB(d.conn)
	match, err := model.NewModelFromString(`
		[request_definition]
		r = sub, obj, act

		[policy_definition]
		p = sub, obj, act
		
		[role_definition]
		g = _, _
		
		[policy_effect]
		e = some(where (p.eft == allow))
		
		[matchers]
		m = r.sub == p.sub && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
		`)
	if err != nil {
		fmt.Println(err)
	}
	enforcer, err := casbin.NewEnforcer(match, adapter)
	if err != nil {
		fmt.Println(err)
	}
	_ = enforcer.LoadPolicy()
	return enforcer
}
